local class = require 'hump.class'
local HC = require 'hardoncollider'
require 'ship'
require 'laser'
require 'utilities.spacephysics'
local state = require 'utilities.state'
require 'planet'
require 'ai'
local tableutils = require 'utilities.tableutils'
require 'utilities.stringfunction'

function onCollision(dt, a, b)
  if a.parent then
    a.parent:onCollide()
  end
  if b.parent then
    b.parent:onCollide()
  end
end

GameServer = class{
  function(self, port)
    self.stringFunction = StringFunction('shipNew', 'running', 'shipIsReady', 'shipRotate', 'shipAccelerate', 'shipShoot', 'shipReady', 'reinitialize', 'state', 'shipColor')
    self.planets = {}
    self.background = 'images/background.png'
    self.ais = {}
    self:reinitialize()
  end
}

function GameServer:command(msg)
  local ret = self.stringFunction:runFunction(msg, self)
  return ret
end

function GameServer:reinitialize()
  self.w = love.graphics.getWidth()
  self.h = love.graphics.getHeight()

  self.collider = HC(100, onCollision)
  local border = 200
  self.borderTop = self.collider:addRectangle(0, -border, self.w, border)
  self.borderBottom = self.collider:addRectangle(0, self.h, self.w, border)
  self.borderLeft = self.collider:addRectangle(-border, -border, border, self.h+border*2)
  self.borderRight = self.collider:addRectangle(self.w, -border, border, self.h+border*2)
  self.collider:setPassive(self.borderTop, self.borderBottom, self.borderLeft, self.borderRight)

  self.spacephysics = SpacePhysics()

  local numPlanets = #self.planets
  self.planets = {}
  self:planetNew(numPlanets)
  self.ships = {}
  for k,v in pairs(self.ais) do
    v:reinitialize()
  end

  self.gameover = false
end

function GameServer:running()
  return not self.gameover
end

function GameServer:state()
  local s = {}
  s['background'] = state.new(self.w/2, self.h/2, self.w, self.h, 0, self.background)
  for k,v in pairs(self.planets) do
    s[k] = v:state()
  end
  for k,v in pairs(self.ships) do
    for kship, vship in pairs(v:state()) do
      s[k..kship] = vship
    end
  end
  return s
end

function GameServer:updateState(dt)
  for k,v in pairs(self.ais) do
    v:update(dt)
  end
  for k,v in pairs(self.ships) do
    v:update(dt)
  end
  self.collider:update(dt)
  self.spacephysics:update(dt)
  
  local numDead = 0
  local num = 0
  for k,v in pairs(self.ships) do
    num = num + 1
    if not v:alive() then
      numDead = numDead + 1
    end
  end
  if numDead+1 >= num then
    self.gameover = true
    for k,v in pairs(self.ships) do
      v:unready()
    end
  end
end

function GameServer:isReady()
  local ret = true
  for k,v in pairs(self.ships) do
    if not self.ships:isReady() then
      ret = false
    end
  end
  return ret
end

function GameServer:planetNew(count)
  if count == nil then
    count = 0
  end
  while #self.planets < count do
    local margin = 100
    local h = self.h-2*margin
    local w = self.w-2*margin
    local minradius = h/(count*10)
    local maxradius = h/(count*3)
    local radius = math.random(minradius, maxradius)
    h = h - radius
    w = w - radius
    local mass = 100e6*radius/maxradius
    local cx = math.random(w/count*#self.planets, w/count*(#self.planets+1))+margin
    local cy = math.random(0, h+margin)
    self.planets[#self.planets+1] = Planet(nil, cx, cy, radius, mass, self.collider, self.spacephysics)
  end
end

function GameServer:shipNew(id)
  local numShips = tableutils.size(self.ships)
  local color = ''
  if numShips == 0 then
    color = 'red'
    self.ships[id] = Ship(color, 50, 50, self.collider, self.spacephysics)
    self:shipRotate(id, -math.pi/4, 1)
  elseif numShips == 1 then
    color = 'blue'
    self.ships[id] = Ship(color, self.w-50, self.h-50, self.collider, self.spacephysics)
    self:shipRotate(id, 3*math.pi/4, 1)
  elseif numShips == 2 then
    color = 'green'
    self.ships[id] = Ship(color, self.w-50, 50, self.collider, self.spacephysics)
    self:shipRotate(id, math.pi/4, 1)
  else
    color = 'yellow'
    self.ships[id] = Ship(color, 50, self.h-50, self.collider, self.spacephysics)
    self:shipRotate(id, -3*math.pi/4, 1)
  end
  return color
end

function GameServer:shipColor(id)
  return self.ships[id]:color()
end

function GameServer:shipRotate(id, angle, dt)
  self.ships[id]:rotate(angle, dt)
end

function GameServer:shipAccelerate(id, dt)
  self.ships[id]:accelerate(dt)
end

function GameServer:shipShoot(id, dt)
  self.ships[id]:shoot(dt)
end

function GameServer:shipReady(id)
  self.ships[id]:ready()
end

function GameServer:shipUnready(id)
  self.ships[id]:unready()
end

function GameServer:shipIsReady(id)
  local ret = false
  if self.ships[id] then
    ret = self.ships[id]:isReady()
  end
  return ret
end

function GameServer:shipIDColorList()
  local list = {}
  for k,v in self.ships do
    list[k] = v:color()
  end
  return list
end

function GameServer:aiNew(aitype)
  self.ais[#self.ais+1] = AI(self, aitype, 'ai' .. #self.ais)
end
